#include <rpc_root.h>
#include <memory>
#include "mock_transport.h"
#include "mock_caller.h"
#include "mock_logger.h"
#ifdef min
#undef min
#endif
#include <cxxopts.hpp>
#include <knet.h>
#include <list>
#include <iostream>

using CallerList = std::list<MockCaller*>;
CallerList callerList;

std::unique_ptr<rpc::RpcImpl> rpc_impl;

void client_cb(kchannel_ref_t* channel, knet_channel_cb_event_e e) {
    if (!rpc_impl) {
        abort();
    }

    if (e & channel_cb_event_recv) {
        auto ptr = rpc::make_shared_ptr<MockTrans>(channel);
        //rpc::onMessage(ptr);
        rpc_impl->onMessage(std::dynamic_pointer_cast<rpc::Transport>(ptr));
    }
}

void acceptor_cb(kchannel_ref_t* channel, knet_channel_cb_event_e e) {
    if (e & channel_cb_event_accept) {
        std::cout << "accepted" << std::endl;
        knet_channel_ref_set_cb(channel, client_cb);
    }
}

int main(int argc, const char** argv) {
    cxxopts::Options option("proxy");
    option.add_options()
        ("h,host", "Host IP", cxxopts::value<std::string>())
        ("p,port", "Host port", cxxopts::value<int>());
    auto result = option.parse(argc, argv);
    std::string ip;
    int port;
    if (!result["host"].count()) {
        std::cerr << "Need host IP" << std::endl;
        std::cerr << option.help();
        return 0;
    }
    ip = result["host"].as<std::string>();
    if (!result["port"].count()) {
        std::cerr << "Need host port" << std::endl;
        std::cerr << option.help();
        return 0;
    }
    port = result["port"].as<int>();
    MockLogger logger;

    rpc_impl = std::make_unique<rpc::RpcImpl>();
    if (rpc_impl == nullptr) {
        logger.write("[RpcMock] init rpc frame work error !!!!!");
        exit(-1);
    }
    //ignore create descriptor for service
    rpc_impl->initialize(&logger);
    std::string soPath;
    // The UUID of 'ServiceDynamic'
    std::string serviceUUID = "5871407834711899994";
#if defined(_WIN32) || defined(_WIN64)
#ifdef _DEBUG
    soPath = "..\\..\\lib\\stub\\example\\ServiceDynamic\\Debug\\libServiceDynamic.so";
#else
    soPath = "..\\..\\lib\\stub\\example\\ServiceDynamic\\Release\\libServiceDynamic.so";
#endif
#else
    soPath = "../lib/stub/example/ServiceDynamic/libServiceDynamic.so";
#endif
    // Try to load shared object for 'ServiceDynamic'
    if (!rpc::loadClass(rpc_impl.get(), serviceUUID, soPath, false, nullptr)) {
        std::cout << "load " << soPath << " failed" << std::endl;
        return 0;
    }
    auto* loop = knet_loop_create();
    auto* acceptor = knet_loop_create_channel(loop, 1024, 1024 * 256);
    knet_channel_ref_set_cb(acceptor, acceptor_cb);
    knet_channel_ref_accept(acceptor, ip.c_str(), port, 512);
    for (;;) {
        knet_loop_run_once(loop);
        rpc_impl->update();
    }
    return 0;
}
